#include "matrixbook.h"
#include "matrixsheet.h"

#include <QTabBar>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSplitter>
#include <QAbstractButton>

static const int ScrollBarWidth = 20;

class MatrixBookPrivate
{
public:
    MatrixBookPrivate(MatrixBook* q);

    void createUi();
    void setCurrentSheet(MatrixSheet* sheet);

    MatrixBook* q_ptr;
    QMap<QString, MatrixSheet*> sheetsMap;

    QTabBar* sheetTab;
    QStackedWidget* tableStack;
    QStackedWidget* hbarStack;
    QStackedWidget* vbarStack;
    QWidget* cornerWidget;
};

MatrixBookPrivate::MatrixBookPrivate(MatrixBook *q) : q_ptr(q)
{
    createUi();
}

void MatrixBookPrivate::createUi()
{
    QVBoxLayout* mainLayout = new QVBoxLayout;
    mainLayout->setContentsMargins(0, 0, 0, 0);

    // top layout
    QHBoxLayout* topLayout = new QHBoxLayout;
    tableStack = new QStackedWidget(q_ptr);
    vbarStack = new QStackedWidget(q_ptr);
    vbarStack->setFixedWidth(ScrollBarWidth);
    topLayout->addWidget(tableStack);
    topLayout->addWidget(vbarStack);

    // bottom layout
    QHBoxLayout* bottomLayout = new QHBoxLayout;
    sheetTab = new QTabBar(q_ptr);
    sheetTab->setExpanding(false);
    sheetTab->setShape(QTabBar::RoundedNorth);

    hbarStack = new QStackedWidget(q_ptr);
    cornerWidget = new QWidget(q_ptr);
    cornerWidget->setFixedSize(ScrollBarWidth, ScrollBarWidth);

    QSplitter* bottomSplitter = new QSplitter(Qt::Horizontal, q_ptr);
    bottomSplitter->addWidget(sheetTab);
    bottomSplitter->addWidget(hbarStack);
    bottomLayout->addWidget(bottomSplitter);
    bottomLayout->addWidget(cornerWidget);

    mainLayout->addLayout(topLayout);
    mainLayout->addLayout(bottomLayout);

    mainLayout->setSpacing(0);
    topLayout->setSpacing(0);
    bottomLayout->setSpacing(0);
    topLayout->setContentsMargins(0, 0, 0, 0);
    bottomLayout->setContentsMargins(0, 0, 0, 0);
    tableStack->setContentsMargins(0, 0, 0, 0);
    vbarStack->setContentsMargins(0, 0, 0, 0);
    hbarStack->setContentsMargins(0, 0, 0, 0);

    q_ptr->setLayout(mainLayout);

    q_ptr->connect(sheetTab, SIGNAL(currentChanged(int)), q_ptr, SLOT(onTabChanged(int)));
}

void MatrixBookPrivate::setCurrentSheet(MatrixSheet* sheet)
{
    tableStack->setCurrentWidget(sheet);
    vbarStack->setCurrentWidget((QWidget*)sheet->verticalScrollBar());
    hbarStack->setCurrentWidget((QWidget*)sheet->horizontalScrollBar());
}

MatrixBook::MatrixBook(QWidget *parent) : QWidget(parent)
{
    d_ptr = new MatrixBookPrivate(this);
}

MatrixBook::~MatrixBook()
{
    delete d_ptr;
}

void MatrixBook::addSheet(MatrixSheet* sheet)
{
    // ignore null sheet
    if (!sheet)
        return;

    // if the sheet is already in the book, ignore op
    if (d_ptr->sheetsMap.contains(sheet->windowTitle()))
        return;

    sheet->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    sheet->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    d_ptr->sheetsMap.insert(sheet->windowTitle(), sheet);
    d_ptr->tableStack->addWidget(sheet);
    d_ptr->vbarStack->addWidget((QWidget*)(sheet->verticalScrollBar()));
    d_ptr->hbarStack->addWidget((QWidget*)(sheet->horizontalScrollBar()));
    d_ptr->sheetTab->addTab(sheet->windowTitle());
}

void MatrixBook::removeSheet(MatrixSheet* sheet)
{
    if (!sheet)
        return;

    QString sheetName = sheet->windowTitle();
    d_ptr->sheetsMap.remove(sheetName);
    int index = -1;
    for (int i = 0; i < d_ptr->sheetTab->count(); ++i) {
        if (d_ptr->sheetTab->tabText(i) == sheetName) {
            index = i;
            break;
        }
    }

    if (index != -1)
        d_ptr->sheetTab->removeTab(index);

    d_ptr->tableStack->removeWidget(sheet);
    d_ptr->vbarStack->removeWidget((QWidget*)sheet->verticalScrollBar());
    d_ptr->hbarStack->removeWidget((QWidget*)sheet->horizontalScrollBar());

    delete sheet;
}

QList<MatrixSheet*> MatrixBook::sheets() const
{
    return d_ptr->sheetsMap.values();
}

void MatrixBook::clear()
{
    QList<MatrixSheet*> sheets = d_ptr->sheetsMap.values();
    qDeleteAll(sheets);
    d_ptr->sheetsMap.clear();
}

void MatrixBook::onTabChanged(int index)
{
    QString sheetName = d_ptr->sheetTab->tabText(index);
    if (d_ptr->sheetsMap.contains(sheetName)) {
        MatrixSheet* sheet = d_ptr->sheetsMap.value(sheetName);
        d_ptr->setCurrentSheet(sheet);
    }
}
